package com.stars.easyms.base.util;

import org.apache.commons.lang3.StringUtils;

/**
 * <p>className: MessageFormatUtil</p>
 * <p>description: 消息占位符转换</p>
 *
 * @author guoguifang
 * @date 2018-10-19 10:07
 * @since 1.0.0
 */
public final class MessageFormatUtil {

    private static final String OPEN_TOKEN = "{";

    private static final String CLOSE_TOKEN = "}";

    private static final Object[] EMPTY_PARAM = new Object[0];

    public static String formatWithToken(final String openToken, final String closeToken, final String message, final Object... params) {
        if (StringUtils.isBlank(openToken) || StringUtils.isBlank(closeToken)) {
            return message;
        }
        return format(openToken, closeToken, message, params != null ? params : EMPTY_PARAM);
    }

    public static String format(final String message, final Object... params) {
        return format(OPEN_TOKEN, CLOSE_TOKEN, message, params != null ? params : EMPTY_PARAM);
    }

    /**
     * 将字符串message中由openToken和closeToken组成的占位符依次替换为params数组中的值：
     * 1.占位符中如果是数字默认为索引，无论传入的params的数量多少占位符中的数字都会被覆盖
     * 2.占位符中如果不是数字则为默认语句，即传入的当前位置的params不存在时默认显示该默认语句，不会被覆盖，如果当前位置的params存在则覆盖
     */
    private static String format(final String openToken, final String closeToken, final String message, final Object... params) {
        int paramLength = params.length;
        if (message == null || message.isEmpty()) {
            StringBuilder sb = new StringBuilder();
            if (paramLength > 0) {
                for (Object param : params) {
                    sb.append(param.toString());
                }
            }
            return sb.toString();
        }

        int offset = 0;
        int start = message.indexOf(openToken, offset);
        if (start == -1) {
            return message;
        }
        int paramsIndex = 0;
        int openTokenLength = openToken.length();
        int closeTokenLength = closeToken.length();
        final StringBuilder builder = new StringBuilder();
        StringBuilder expression = null;
        char[] src = message.toCharArray();
        int scrLength = src.length;
        while (start > -1) {
            if (start > 0 && src[start - 1] == '\\') {
                builder.append(src, offset, start - offset - 1).append(openToken);
                offset = start + openTokenLength;
            } else {
                if (expression == null) {
                    expression = new StringBuilder();
                } else {
                    expression.setLength(0);
                }
                builder.append(src, offset, start - offset);
                offset = start + openTokenLength;
                int end = message.indexOf(closeToken, offset);
                while (end > -1) {
                    if (end > offset && src[end - 1] == '\\') {
                        expression.append(src, offset, end - offset - 1).append(closeToken);
                        offset = end + closeTokenLength;
                        end = message.indexOf(closeToken, offset);
                    } else {
                        expression.append(src, offset, end - offset);
                        break;
                    }
                }
                if (end == -1) {
                    builder.append(src, start, scrLength - start);
                    offset = scrLength;
                } else {
                    String value;
                    if (paramsIndex <= paramLength - 1) {
                        value = params[paramsIndex] == null ? "" : params[paramsIndex].toString();
                    } else {
                        value = expression.toString().matches("^\\d+$") ? "" : expression.toString();
                    }
                    builder.append(value);
                    offset = end + closeTokenLength;
                    paramsIndex++;
                }
            }
            start = message.indexOf(openToken, offset);
        }
        if (offset < scrLength) {
            builder.append(src, offset, scrLength - offset);
        }
        return builder.toString();
    }

    private MessageFormatUtil() {
    }
}
